from airconfig.config import config
from operator import attrgetter
from scheduler import views
import datetime
import math
from common.models import Detail

scheduler = views.scheduler
# 请求对象
class Request():
    def __init__(self, roomid: str, currentTemp: float, targetTemp: float,
                 fanSpeed: str, feeRate: float, tempRate: float, workmode: str):
        self.room_id = roomid
        self.currentTemp = currentTemp
        # 从master中获取管理员设置的默认值
        self.targetTemp = targetTemp
        self.fanSpeed = fanSpeed
        self.feeRate = feeRate
        self.tempRate = tempRate
        self.workmode = workmode
        # 默认值
        self.fee = 0.0
        #修改分界线
        self.serviceTime = 0  # 服务时长
        self.waitTime = 0       # 等待时长
        # 等进入服务队列时赋值
        self.serviceStartTime = None   # 进入服务队列的时间
        self.serviceStopTime = None    # 退出服务队列的时间
        self.waitStartTime = None      # 进入等待队列的时间
        self.waitStopTime = None       # 退出等待队列的时间
        self.detailTime = None         # 上一次生成详单时间
        # 等待计时器器是否启动中 0-否 1-是
        self.ifWait = 0
        # 温度计时器是否启动中 0-否 1-是
        self.iftemp = 0


# 调度员
class Scheduler():
    def __init__(self):
        self.service_list: list[Request] = []  # 服务队列
        self.wait_list: list[Request] = []  # 等待队列
        self.pause_list: list[Request] = []  # 暂停队列

    def add_service(self, request: Request):
        print(request.room_id + "add_service")
        request.serviceStartTime = datetime.datetime.now()
        self.service_list.append(request)
        self.show_pos()

    def add_wait(self, request: Request):
        print(request.room_id + "add_wait")
        request.waitStartTime = datetime.datetime.now()
        request.ifWait = 1
        scheduler.add_job(wait_over, 'date', id=request.room_id + 'wait',
                          run_date=(datetime.datetime.now() + datetime.timedelta(seconds=config.wait_interval)),
                          args=[request.room_id])
        self.wait_list.append(request)
        self.show_pos()

    def delete_if_exists(self, room_id):
        print(room_id + "delete")
        for item in self.service_list:
            if item.room_id == room_id:
                return self.delete_service(room_id)
        for item in self.wait_list:
            if item.room_id == room_id:
                return self.delete_wait(room_id)
        for item in self.pause_list:
            if item.room_id == room_id:
                return self.delete_pause(room_id)

    def delete_service(self, room_id: str):
        print(room_id + "delete_service")
        for i in range(len(self.service_list)):
            if self.service_list[i].room_id == room_id:
                self.service_list[i].serviceStopTime = datetime.datetime.now()     # 记录退出服务队列的时间
                self.service_list[i].serviceTime = self.service_count(room_id)  # 计算服务时长
                return self.service_list.pop(i)

    def delete_wait(self, room_id: str):
        print(room_id + "delete_wait")
        self.show_pos()
        for i in range(len(self.wait_list)):
            if self.wait_list[i].room_id == room_id:
                print(self.wait_list[i],self.wait_list[i].room_id,self.wait_list[i].ifWait)
                self.wait_list[i].waitStopTime = datetime.datetime.now()            # 记录退出等待队列的时间
                self.wait_list[i].waitTime = self.wait_count(room_id)                # 计算等待时长
                if self.wait_list[i].ifWait == 1:
                    scheduler.remove_job(job_id=(room_id + 'wait'))
                    self.wait_list[i].ifWait = 0
                return self.wait_list.pop(i)

    def delete_pause(self, room_id: str):
        print(room_id + "delete_pause")
        for i in range(len(self.pause_list)):
            if self.pause_list[i].room_id == room_id:
                return self.pause_list.pop(i)

    def move_to_pause(self, request):
        print(request.room_id + "move_to_pause")
        s = self.delete_service(request.room_id)
        self.pause_list.append(s)

    def move_to_wait(self, request):
        print(request.room_id + "move_to_wait")
        s = self.delete_service(request.room_id)
        self.add_wait(s)
        return s

    def move_to_service(self, request):
        print(request.room_id + "move_to_service")
        s = self.delete_wait(request.room_id)
        self.add_service(s)
        return s

    def get_request(self, room_id):
        print(room_id + "get_request")
        for item in self.service_list:
            if item.room_id == room_id:
                return item
        for item in self.wait_list:
            if item.room_id == room_id:
                return item
        for item in self.pause_list:
            if item.room_id == room_id:
                return item
        return None

    def get_request_pos(self, room_id):
        print(room_id + "get_request_pos")
        for item in self.service_list:
            if item.room_id == room_id:
                return 'service'
        for item in self.wait_list:
            if item.room_id == room_id:
                return 'wait'
        for item in self.pause_list:
            if item.room_id == room_id:
                return 'pause'
        return None

    # 结束等待的请求，返回来处理
    def wait_over(self, room_id):
        print(room_id + "wait_over")
        request = self.get_request(room_id)
        # print("Before wait_over",request.room_id, request.ifWait)
        request.ifWait = 0
        # 风速最低，服务时间最长的请求对象
        self.fresh_service_time()
        # self.service_list.sort(key=attrgetter('fanSpeed', 'serviceTime'))
        self.service_list = sorted(self.service_list, key=lambda x: (x.fanSpeed, -x.serviceTime))
        # 如果风速最低、服务时间最长的请求的风速小于等于结束等待的请求，就处理
        if self.service_list[0].fanSpeed <= request.fanSpeed:
            # 生成详单
            s = self.service_list[0]
            create_Detail(s.room_id, s.serviceStartTime, self.get_time(s.room_id), s.fanSpeed, s.feeRate, s.fee, "schedule_kick",datetime.datetime.now())
            s.detailTime = datetime.datetime.now()
            self.move_to_wait(self.service_list[0])
            # print("After wait_over", request, request.room_id, request.ifWait)
            self.move_to_service(request)

    # 调度等待队列
    def wait_to_service(self):
        print("wait_to_service")
        if len(self.wait_list) == 0 or len(self.service_list) == config.max_run:
            return
        self.fresh_wait_time()
        self.wait_list.sort(key=attrgetter('fanSpeed','waitTime'),reverse=True)
        # 等待队列中风速最大，等待时间最长的请求对象加入服务队列
        s = self.delete_wait(self.wait_list[0].room_id)
        self.add_service(s)
        return s

    # 处理新请求
    def new_request(self, request:Request):
        print(request.room_id + "new_request")
        self.show_pos()
        # 定时计算温度
        if request.iftemp == 0:
            scheduler.add_job(temp_count, 'interval', id=(request.room_id + 'temp'),
                              seconds=config.cal_interval,
                              args=[request.room_id])
            request.iftemp = 1
        if len(self.service_list) < config.max_run:
            self.add_service(request)
        else:
            # 风速最低，服务时间最长的请求对象
            self.fresh_service_time()
            # self.service_list.sort(key=attrgetter('fanSpeed', 'serviceTime'))
            self.service_list = sorted(self.service_list, key=lambda x: (x.fanSpeed, -x.serviceTime))
            for item in self.service_list:
                print(item.room_id +" "+ str(item.fanSpeed) +" "+ str(item.serviceTime))
            print(self.service_list[0].fanSpeed,request.fanSpeed)
            if self.service_list[0].fanSpeed < request.fanSpeed:
                # 优先级更高
                # 生成详单
                s = self.service_list[0]
                create_Detail(s.room_id, s.serviceStartTime, self.get_time(s.room_id), s.fanSpeed, s.feeRate, s.fee, "schedule_kick",datetime.datetime.now())
                s.detailTime = datetime.datetime.now()
                self.move_to_wait(self.service_list[0])
                self.add_service(request)
            else:
                # 优先级低
                self.add_wait(request)

    def change_fan_speed(self, room_id):
        print(room_id + "change_fan_speed")
        pos = self.get_request_pos(room_id)
        s = self.delete_if_exists(room_id)
        print(pos)
        if pos == 'service':
            self.wait_to_service()
        # 加入新请求
        self.new_request(s)

    # def change_goal_temp(self, room_id, goal_temp):
    #     print("change_goal_temp")
    #     s = self.get_request(room_id)
    #     # 考虑温度合法性？？？ 要求4
    #     s.targetTemp = goal_temp

    def one_room_power_off(self, room_id):
        print(room_id + "one_room_power_off")
        request = self.get_request(room_id)
        if request.iftemp == 1:
            scheduler.remove_job(job_id=(room_id + 'temp'))
        self.delete_if_exists(room_id)
        self.wait_to_service()

    def one_room_power_on(self, request):
        print(request.room_id + "one_room_power_on")
        self.new_request(request)

    def one_room_pause(self, room_id):
        print(room_id + "one_room_pause")
        request = self.get_request(room_id)
        # 将当前房间加入停止队列
        self.move_to_pause(request)
        # 选择一个等待队列中的请求对象加入服务队列
        self.wait_to_service()

    def one_room_restart(self, room_id):
        print(room_id + "one_room_restart")
        s = self.delete_pause(room_id)
        self.new_request(s)

    def temp_count(self,room_id):
        print(room_id + "temp_count")
        # print("定时计算温度")
        request = self.get_request(room_id)
        pos = self.get_request_pos(room_id)
        if pos == "service":
            self.cal_service_temp(room_id)
        elif pos == "wait":
            self.cal_wait_temp(room_id)
        else:
            self.cal_pause_temp(room_id)
        print(request.currentTemp)

    def service_count(self,room_id):
        print(room_id + "service_count")
        # print("需要时计算服务时长")
        request = self.get_request(room_id)
        pos = self.get_request_pos(room_id)
        if pos == 'service':
            return (datetime.datetime.now() - request.serviceStartTime).seconds
        else:
            return request.serviceTime

    def wait_count(self,room_id):
        print(room_id + "wait_count")
        request = self.get_request(room_id)
        pos = self.get_request_pos(room_id)
        if pos == 'wait':
            return (datetime.datetime.now() - request.waitStartTime).seconds
        else:
            return request.waitTime

    def cal_service_temp(self, room_id):
        print(room_id + "cal_service_temp")
        s = self.get_request(room_id)
        curr_temp = s.currentTemp
        goal_temp = s.targetTemp
        temp_rate = s.tempRate
        curr_temp = cal_curr_temp(curr_temp, goal_temp, temp_rate)
        # 记录温度和费用
        s.currentTemp = curr_temp
        # 达到目标温度
        if math.isclose(goal_temp, curr_temp) is True:
            # 生成详单
            s.serviceTime = self.service_count(s.room_id)
            create_Detail(s.room_id, s.serviceStartTime, self.get_time(s.room_id), s.fanSpeed, s.feeRate, s.fee, "target_temp",datetime.datetime.now())
            s.detailTime = datetime.datetime.now()
            self.one_room_pause(s.room_id)

    def cal_wait_temp(self, room_id):
        print(room_id + "cal_wait_temp")
        s = self.get_request(room_id)
        curr_temp = s.currentTemp
        # env_temp = config.room_temp
        env_temp = s.currentTemp        # 改成等待队列不回温
        temp_rate = s.tempRate
        if math.isclose(env_temp, curr_temp) is not True:
            curr_temp = cal_curr_temp(curr_temp, env_temp, temp_rate)
            s.currentTemp = curr_temp

    def cal_pause_temp(self, room_id):
        print(room_id + "cal_pause_temp")
        s = self.get_request(room_id)
        curr_temp = s.currentTemp
        if s.workmode == -1:
            env_temp = config.default_current_temp_cold[s.room_id]
        else:
            env_temp = config.default_current_temp_hot[s.room_id]
        goal_temp = s.targetTemp
        temp_rate = s.tempRate
        #  和目标温度温差尚未达到1度
        if (s.workmode == -1 and (curr_temp - goal_temp) < 1) or (s.workmode == 1 and (goal_temp - curr_temp) < 1):
            # 未回落到室温
            if math.isclose(env_temp, curr_temp) is not True:
                curr_temp = cal_curr_temp(curr_temp, env_temp, temp_rate)
                s.currentTemp = curr_temp
        print(curr_temp,goal_temp)
        # 结束回温
        if s.workmode == -1 and (curr_temp - goal_temp) >= 1:
            self.one_room_restart(s.room_id)
        elif s.workmode == 1 and (goal_temp - curr_temp) >= 1:
            self.one_room_restart(s.room_id)
        elif math.isclose(goal_temp, curr_temp) is True:
            self.one_room_restart(s.room_id)

    def fresh_service_time(self):
        print("fresh_service_time")
        for item in self.service_list:
            item.serviceTime = self.service_count(item.room_id)

    def fresh_wait_time(self):
        print("fresh_wait_time")
        for item in self.wait_list:
            item.waitTime = self.wait_count(item.room_id)

    def get_time(self, room_id):
        request = self.get_request(room_id)
        pos = self.get_request_pos(room_id)
        if pos == 'service':
            if request.detailTime is None or request.detailTime < request.serviceStartTime:
                return (datetime.datetime.now() - request.serviceStartTime).seconds
            else:
                return (datetime.datetime.now() - request.detailTime).seconds
        else:
            if request.detailTime is None or request.detailTime < request.serviceStartTime:
                return request.serviceTime
            else:
                return (request.serviceStopTime - request.detailTime).seconds

    def show_pos(self):
        print("service:")
        for item in self.service_list:
            print(item.room_id + " ",end="")
        print("\nwait:")
        for item in self.wait_list:
            print(item.room_id + " ",end="")
        print("\npause:")
        for item in self.pause_list:
            print(item.room_id + " ",end="")
        print("")

sche = Scheduler()

def wait_over(request):
    sche.wait_over(request)

def temp_count(room_id):
    sche.temp_count(room_id)

def cal_curr_temp(curr_temp, target_temp, rate):
    if target_temp > curr_temp:
        curr_temp += rate * config.cal_interval / 60
        curr_temp = min(target_temp, curr_temp)
    else:
        curr_temp -= rate * config.cal_interval / 60
        curr_temp = max(target_temp, curr_temp)
    return curr_temp

def create_Detail(room_id, lastinTime, requestDuration, fanSpeed, feeRate, fee, cmd, time):
    # 创建详单
    record = Detail.objects.create(rid=room_id,
                                   lastinTime=lastinTime.replace(microsecond=0),
                                   requestDuration=requestDuration,
                                   fanSpeed=fanSpeed,
                                   feeRate=feeRate,
                                   fee=fee,
                                   cmd=cmd,
                                   createTime=time.replace(microsecond=0))
    record.save()